package ex;

import org.apache.commons.math3.util.Combinations;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Objects;
import java.util.Scanner;

/**
 * @Description 将原有的先把所有组合找出修改为一次一次迭代找出组合
 * @Date 2022/3/21 10:39
 * @Author eric ling
 */
public class IteratorSearch {
    /*
        边界验证：nCk 当k=0时
        DSP(13,6,6,0,3) D1={1,3,9,4,12,10} D2={2,6,5,7,8,11}
        DSP(17,8,8,0,4) D1={1,2,4,8,16,15,13,9} D2={3,6,12,7,14,11,5,10}

        小范围
        DSP(15,3,5,1,1) D1={0,5,10} D2={0,3,6,9,12}
        DSP(13,6,7,6,3) D={1,3,4,9,10,12} D2={1,3,4,9,10,12,0}

        大范围
        DSP(31,11,6,6,2)
        DSP(51,26,16,16,8)
        DSP(57,29,20,20,10)
        DSP(69,35,24,24,12)
        DSP(73,54,19,18,14)

        构造DSP
        DSP(4v+1,2v,2v,0,v)
        DSP(4v+1,2v+1,2v,2v,v)
    */
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入系统变量v,k1,k2,e,lambda，例如：15,3,5,1,1");
        String[] numStrs = scanner.nextLine().split("[,;\\s]+");
        int[] nums = new int[5];
        int tmpIdx = 0;
        for (String numStr : numStrs) {
            nums[tmpIdx++] = Integer.parseInt(numStr);
        }

        // 利用必要条件预筛选给定差集偶的参数
        while (!DiffSetPair.isValid(nums)) {
            // 给定参数不合法
            System.out.println("给定参数不存在差集偶，请重新输入：");
            numStrs = scanner.nextLine().split("[,;\\s]+");
            tmpIdx = 0;
            for (String numStr : numStrs) {
                nums[tmpIdx++] = Integer.parseInt(numStr);
            }
        }
        System.out.println("searching...");

        File file = new File("result_" + Arrays.toString(nums) + "_" + LocalDate.now() + "_iteratorSearch.txt");
        if (!file.exists()) {
            try {
                System.out.println("create file result.txt:" + file.createNewFile());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        DiffSetPair p = new DiffSetPair(nums);
        try (FileWriter writer = new FileWriter(file)) {
            System.out.println("共搜索到" + run(p, writer) + "个满足给定参数的差集偶");
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("搜索耗时：" + (end - start) + "毫秒");
        System.out.println("差集偶搜索完毕，结果保存在" + file.getAbsolutePath());
    }

    public static int run(DiffSetPair p, Writer writer) throws IOException {
        int find = 0;
        // 所有的数从该集合中选取
        boolean[] remainderSetIdx = new boolean[p.getV()]; // 用下标表示集合元素，存放的boolean表示是否存在集合中
        Arrays.fill(remainderSetIdx, true);

        if (p.getE() == 0) {
            p.seteSet(new int[0]);
            // nCk k为0 额外的处理逻辑
            // 开始迭代k2Set
            for (int[] k2SetIdx : new Combinations(p.getV(), p.getK2())) {
                // System.out.println(Arrays.toString(k2SetIdxCombIter.next()));
                boolean[] remainderSetIdx1 = remainderSetIdx.clone();
                int[] k2Set = ArrayHandler.extractCombElement(remainderSetIdx1, k2SetIdx);
                // 确定集合k2Set
                p.setK2Set(k2Set);

                // 开始迭代k1Set
                for (int[] k1SetIdx : new Combinations(p.getV() - p.getK2(), p.getK1())) {
                    boolean[] remainderSetIdx2 = remainderSetIdx1.clone();
                    int[] k1Set = ArrayHandler.extractCombElement(remainderSetIdx2, k1SetIdx);
                    // 确定集合k1Set
                    p.setK1Set(k1Set);

                    // k1Set和k2Set都确定了，开始判断是否构成差集偶
                    if (p.isDiffSetPair()) {
                        find++;
                        System.out.println(p);
                        writer.write(p + "\n");
                    }
                }
            }

        } else {
            // 迭代集合E的所有可能组合
            if (p.getE() == p.getK1() && p.getE() == p.getK2()) {
                for (int[] eSetIdx : new Combinations(p.getV(), p.getE())) {
                    boolean[] remainderSetIdx1 = remainderSetIdx.clone();
                    int[] eSet = ArrayHandler.extractCombElement(remainderSetIdx1, eSetIdx);
                    p.seteSet(eSet);
                    p.setK1Set(eSet);
                    p.setK2Set(eSet);
                    // k1Set和k2Set都确定了，开始判断是否构成差集偶
                    if (p.isDiffSetPair()) {
                        find++;
                        System.out.println(p);
                        writer.write(p + "\n");
                    }
                }
            } else if (p.getE() == p.getK2() && p.getE() != p.getK1()) {
                for (int[] eSetIdx : new Combinations(p.getV(), p.getE())) {
                    boolean[] remainderSetIdx1 = remainderSetIdx.clone();
                    int[] eSet = ArrayHandler.extractCombElement(remainderSetIdx1, eSetIdx);
                    p.seteSet(eSet);
                    p.setK2Set(eSet);

                    for (int[] k1Set_eSetIdx : new Combinations(p.getV() - p.getK2(), p.getK1() - p.getE())) {
                        boolean[] remainderSetIdx2 = remainderSetIdx1.clone();
                        int[] k1Set_eSet = ArrayHandler.extractCombElement(remainderSetIdx2, k1Set_eSetIdx);
                        p.setK1Set(ArrayHandler.concat(k1Set_eSet, eSet));

                        // k1Set和k2Set都确定了，开始判断是否构成差集偶
                        if (p.isDiffSetPair()) {
                            find++;
                            System.out.println(p);
                            writer.write(p + "\n");
                        }
                    }
                }
            } else if (p.getE() == p.getK1() && p.getE() != p.getK2()) {
                for (int[] eSetIdx : new Combinations(p.getV(), p.getE())) {
                    boolean[] remainderSetIdx1 = remainderSetIdx.clone();
                    int[] eSet = ArrayHandler.extractCombElement(remainderSetIdx1, eSetIdx);
                    p.seteSet(eSet);
                    p.setK1Set(eSet);

                    for (int[] k2Set_eSetIdx : new Combinations(p.getV() - p.getK1(), p.getK2() - p.getE())) {
                        boolean[] remainderSetIdx2 = remainderSetIdx1.clone();
                        int[] k2Set_eSet = ArrayHandler.extractCombElement(remainderSetIdx2, k2Set_eSetIdx);
                        p.setK2Set(ArrayHandler.concat(k2Set_eSet, eSet));

                        // k1Set和k2Set都确定了，开始判断是否构成差集偶
                        if (p.isDiffSetPair()) {
                            find++;
                            System.out.println(p);
                            writer.write(p + "\n");
                        }
                    }
                }
            } else {
                for (int[] eSetIdx : new Combinations(p.getV(), p.getE())) {
                    boolean[] remainderSetIdx1 = remainderSetIdx.clone();
                    int[] eSet = ArrayHandler.extractCombElement(remainderSetIdx1, eSetIdx);
                    p.seteSet(eSet);
                    for (int[] k2Set_eSetIdx : new Combinations(p.getV() - p.getE(), p.getK2() - p.getE())) {
                        boolean[] remainderSetIdx2 = remainderSetIdx1.clone();
                        int[] k2Set_eSet = ArrayHandler.extractCombElement(remainderSetIdx2, k2Set_eSetIdx);
                        p.setK2Set(ArrayHandler.concat(k2Set_eSet, eSet));
                        for (int[] k1Set_eSetIdx : new Combinations(p.getV() - p.getK2(), p.getK1() - p.getE())) {
                            boolean[] remainderSetIdx3 = remainderSetIdx2.clone();
                            int[] k1Set_eSet = ArrayHandler.extractCombElement(remainderSetIdx3, k1Set_eSetIdx);
                            p.setK1Set(ArrayHandler.concat(k1Set_eSet, eSet));

                            // k1Set和k2Set都确定了，开始判断是否构成差集偶
                            if (p.isDiffSetPair()) {
                                find++;
                                System.out.println(p);
                                writer.write(p + "\n");
                            }
                        }
                    }
                }
            }
        }
        return find;
    }
}
